module boundary_mod

  use namelist_mod

  implicit none

  private
  public boundary_init
  public set_periodic_boundary
  public pbc_idx

  interface
    subroutine set_periodic_boundary_interface(var)
      import :: r8, nx, nhalo
      real(r8), intent(inout) :: var(1-nhalo:nx+nhalo)
    end subroutine set_periodic_boundary_interface
    integer function pbc_idx_interface(i, nx)
      integer, intent(in) :: i, nx
    end function pbc_idx_interface
  end interface

  procedure(set_periodic_boundary_interface), pointer :: set_periodic_boundary
  procedure(pbc_idx_interface              ), pointer :: pbc_idx 

contains

  subroutine boundary_init()

    select case (trim(space_scheme))
    case ('MCV')
      set_periodic_boundary => set_periodic_boundary_MCV
      pbc_idx => pbc_idx_MCV
    case default
      set_periodic_boundary => set_periodic_boundary_normal
      pbc_idx => pbc_idx_normal
    end select

  end subroutine boundary_init 

  subroutine set_periodic_boundary_normal(var)
    
    real(r8), intent(inout) :: var(1-nhalo:nx+nhalo)
    integer i

    do i = 1, nhalo
      var(1-i)  = var(nx-i+1)
      var(nx+i) = var(i)
    end do

  end subroutine set_periodic_boundary_normal

  integer function pbc_idx_normal(i, nx)

    integer, intent(in) :: i, nx
  
    if (i < 1) then
      pbc_idx_normal = nx + i  ! q(-1)=q(nx-1), q(0)=q(nx)
    else if (i > nx) then
      pbc_idx_normal = i - nx  ! q(nx+1)=q(1), q(nx+2)=q(2)
    else
      pbc_idx_normal = i
    end if

  end function pbc_idx_normal

  subroutine set_periodic_boundary_MCV(var)
    
    real(r8), intent(inout) :: var(1-nhalo:nx+nhalo)
    integer i

    do i = 1, nhalo
      var(1-i)  = var(nx-i)
      var(nx+i) = var(i+1)
    end do

  end subroutine set_periodic_boundary_MCV

  integer function pbc_idx_MCV(i, nx)

    integer, intent(in) :: i, nx
  
    if (i < 1) then
      pbc_idx_MCV = nx - 1 + i  ! q(-1)=q(nx-2), q(0)=q(nx-1)
    else if (i > nx) then
      pbc_idx_MCV = i - nx + 1  ! q(nx+1)=q(2), q(nx+2)=q(3)
    else
      pbc_idx_MCV = i
    end if

  end function pbc_idx_MCV

end module boundary_mod